// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

(function(mod) {
  if (typeof exports == 'object' && typeof module == 'object')
    // CommonJS
    mod(require('../../lib/codemirror'));
  else if (typeof define == 'function' && define.amd)
    // AMD
    define(['../../lib/codemirror'], mod);
  // Plain browser env
  else mod(CodeMirror);
})(function(CodeMirror) {
  'use strict';

  CodeMirror.defineMode('spreadsheet', function() {
    return {
      startState: function() {
        return {
          stringType: null,
          stack: [],
        };
      },
      token: function(stream, state) {
        if (!stream) return;

        //check for state changes
        if (state.stack.length === 0) {
          //strings
          if (stream.peek() == '"' || stream.peek() == "'") {
            state.stringType = stream.peek();
            stream.next(); // Skip quote
            state.stack.unshift('string');
          }
        }

        //return state
        //stack has
        switch (state.stack[0]) {
          case 'string':
            while (state.stack[0] === 'string' && !stream.eol()) {
              if (stream.peek() === state.stringType) {
                stream.next(); // Skip quote
                state.stack.shift(); // Clear flag
              } else if (stream.peek() === '\\') {
                stream.next();
                stream.next();
              } else {
                stream.match(/^.[^\\\"\']*/);
              }
            }
            return 'string';

          case 'characterClass':
            while (state.stack[0] === 'characterClass' && !stream.eol()) {
              if (!(stream.match(/^[^\]\\]+/) || stream.match(/^\\./)))
                state.stack.shift();
            }
            return 'operator';
        }

        var peek = stream.peek();

        //no stack
        switch (peek) {
          case '[':
            stream.next();
            state.stack.unshift('characterClass');
            return 'bracket';
          case ':':
            stream.next();
            return 'operator';
          case '\\':
            if (stream.match(/\\[a-z]+/)) return 'string-2';
            else {
              stream.next();
              return 'atom';
            }
          case '.':
          case ',':
          case ';':
          case '*':
          case '-':
          case '+':
          case '^':
          case '<':
          case '/':
          case '=':
            stream.next();
            return 'atom';
          case '$':
            stream.next();
            return 'builtin';
        }

        if (stream.match(/\d+/)) {
          if (stream.match(/^\w+/)) return 'error';
          return 'number';
        } else if (stream.match(/^[a-zA-Z_]\w*/)) {
          if (stream.match(/(?=[\(.])/, false)) return 'keyword';
          return 'variable-2';
        } else if (['[', ']', '(', ')', '{', '}'].indexOf(peek) != -1) {
          stream.next();
          return 'bracket';
        } else if (!stream.eatSpace()) {
          stream.next();
        }
        return null;
      },
    };
  });

  CodeMirror.defineMIME('text/x-spreadsheet', 'spreadsheet');
});
